package com.carleasoft.mps.adu.business.dept.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carleasoft.mps.adu.business.dept.bean.entity.DeptEntity;
import com.carleasoft.mps.adu.business.dept.bean.po.DeptPagePo;
import com.carleasoft.mps.adu.business.dept.bean.po.DeptPo;
import com.carleasoft.mps.adu.business.dept.bean.vo.DeptDetailVo;
import com.carleasoft.mps.adu.business.dept.bean.vo.DeptTreeVo;
import com.carleasoft.mps.adu.business.dept.dao.DeptDao;
import com.carleasoft.mps.adu.business.dept.service.DeptService;
import com.carleasoft.mps.adu.business.dept.service.IAuthorityDeptTypeService;
import com.carleasoft.mps.adu.business.org.service.OrgService;
import com.carleasoft.mps.adu.business.position.bean.po.AuthorityPositionGroupPo;
import com.carleasoft.mps.adu.business.position.service.AuthorityPositionGroupService;
import com.carleasoft.mps.adu.business.user.bean.entity.AuthorityUserDept;
import com.carleasoft.mps.adu.business.user.service.AuthorityUserDeptService;
import com.carleasoft.mps.adu.common.constants.BusinessErrorEnum;
import com.carleasoft.mps.core.exceptions.BusinessException;
import com.carleasoft.mps.core.user.*;
import com.carleasoft.mps.core.utils.ConvertUtils;
import com.carleasoft.mps.core.utils.DateUtil;
import com.carleasoft.mps.core.utils.ExceptionUtil;
import com.carleasoft.mps.security.permission.data.RequiresDataPermission;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * <p>Description: dept serviceImpl </p>
 *
 * @author ztm
 * @since 2020/4/29
 */
@Service
public class DeptServiceImpl extends ServiceImpl<DeptDao, DeptEntity> implements DeptService {

    @Autowired
    AuthorityUserDeptService authorityUserDeptService;
    @Autowired
    AuthorityPositionGroupService authorityPositionGroupService;
    @Autowired
    OrgService orgService;
    @Autowired
    DeptDao deptDao;
    @Autowired
    IAuthorityDeptTypeService iAuthorityDeptTypeService;



    /**
     * @param deptPagePo
     * @return
     */
    @Override
    @RequiresDataPermission(dataPerm = {@RequiresDataPermission.Scope(method = "selectDeptTree",scope = Constants.DATA_SCOPE_ORG)})
    public List<DeptTreeVo> treePageDept(DeptPagePo deptPagePo) {
        List<DeptTreeVo> deptTreeVos=this.deptDao.selectDeptTree(deptPagePo,Constants.PARENT_CODE);
       return this.buildTree(deptTreeVos);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean updateSort(SortPo sortPo) {
        boolean result = false;
        if (sortPo.getSort() == null) {
            //自己
            DeptEntity own = this.getById(sortPo.getOwnCode());
            Integer ownSort = own.getSort();
            Long ownSortDate = own.getSortDate();
            DeptEntity down = this.getById(sortPo.getMoveCode());
            Integer sort = down.getSort();
            Long sortDate = down.getSortDate();

            own.setSort(sort);
            own.setSortDate(sortDate);
            result = this.updateById(own);
            down.setSort(ownSort);
            down.setSortDate(ownSortDate);
            result = this.updateById(down);
        } else {
            LambdaUpdateWrapper<DeptEntity> wrapper = Wrappers.<DeptEntity>lambdaUpdate();
            wrapper.eq(DeptEntity::getId, sortPo.getOwnCode());
            wrapper.set(DeptEntity::getSortDate, DateUtil.getEpochSecond());
            wrapper.set(DeptEntity::getSort, sortPo.getSort());
            result = this.update(wrapper);

        }
        result=this.authorityPositionGroupService.updateSort(sortPo);
        return result;
    }

    @Override
    public List<DeptEntity> getByDeptList(DeptPagePo deptPagePo) {

        return this.deptDao.selectDeptListByParentDeptCode(deptPagePo,Constants.PARENT_CODE);
    }

    @Override
    public DeptEntity getByDeptCode(String code) {
        return this.getOne(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getDeptCode,code));
    }

    @Override
    public List<DeptEntity> getDeptAll() {
        List<DeptEntity> deptEntities = this.list();
        return deptEntities;
    }

    @Override
    public List<DeptTreeVo> deptTree() {
        List<DeptTreeVo> returnList = new LinkedList<>();
        List<DeptEntity> allList = this.list(new QueryWrapper<DeptEntity>().eq("DEPT_STATUS", 1).ne("DEPT_CODE","0000"));
        if (allList==null || allList.size()<=0){
            return null;
        }
        List<DeptEntity> topList = allList.stream().filter(a -> {
            return a.getParentDeptCode().equals("0");
        }).collect(toList());
        if (topList!=null && topList.size()>0){
            topList.stream().forEach(a->{
                DeptTreeVo vo = new DeptTreeVo();
                BeanUtils.copyProperties(a,vo);
                returnList.add(vo);
            });
            return diGuiDeptTree(allList,returnList);

        }
        return returnList;
    }

    
    /**
     * @author zang
     * @desc 获取子部门
     * @date 2023-10-23
     */
    @Override
    public List<DeptEntity> deptChildTree(DeptTreeVo deptTreeVo) {
        List<DeptEntity> res = new ArrayList<>();
        if(StringUtils.isNotBlank(deptTreeVo.getParentDeptCode())){
            res = this.list(new QueryWrapper<DeptEntity>().eq("PARENT_DEPT_CODE",deptTreeVo.getParentDeptCode()));
        } else {
            res = this.list(new QueryWrapper<DeptEntity>().eq("PARENT_DEPT_CODE","0"));
        }
        return res;
    }
    
    
    /**
     * 添加部门或机构
     * ok
     *
     * @param deptPo 部门实体
     * @return 部门编码
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public DeptEntity add(DeptPo deptPo) {

        //查看部门名称是否重复
            int count = this.count(Wrappers.<DeptEntity>lambdaQuery()
                    .eq(DeptEntity::getDeptName, deptPo.getDeptName())
                    .eq(DeptEntity::getParentDeptCode,deptPo.getParentDeptCode())
                    .eq(DeptEntity::getOrganizationCode,deptPo.getOrganizationCode()));
            if (count > 0) {
                throw ExceptionUtil.create(BusinessErrorEnum.DEPT_NAME_REPEAT);
            }
            if(StrUtil.isNotBlank(deptPo.getDeptNumber())&&this.count(Wrappers.<DeptEntity>lambdaQuery()
                    .eq(DeptEntity::getDeptNumber, deptPo.getDeptNumber())
                    .eq(DeptEntity::getParentDeptCode,deptPo.getParentDeptCode())
                    .eq(DeptEntity::getOrganizationCode,deptPo.getOrganizationCode()))>0){
                throw ExceptionUtil.create(BusinessErrorEnum.DEPT_NUMBER_REPEAT);
            }
            DeptEntity deptEntity = ConvertUtils.sourceToTarget(deptPo, DeptEntity.class);
            if (StrUtil.isBlank(deptPo.getDeptCode())){
                String code = IdWorker.getIdStr();
                deptEntity.setDeptCode(code);
            }
            if(StrUtil.isBlank(deptEntity.getParentDeptCode())){
                deptEntity.setParentDeptCode(Constants.PARENT_CODE);
                deptEntity.setDeptName(deptEntity.getDeptName()+Constants.DEPT_SUFFIX);
                deptEntity.setFullPath(deptEntity.getDeptCode());
            } else {
                DeptEntity parent = this.getOne(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getDeptCode, deptPo.getParentDeptCode()));
                deptEntity.setOrganizationCode(parent.getOrganizationCode());
                deptEntity.setFullPath(parent.getFullPath()+Constants.DELIMITER+deptEntity.getDeptCode());
            }
           deptEntity.setDeptStatus(Constants.ENABLE);
        if(Objects.isNull(deptPo.getSort())) {
            DeptEntity sortType = this.getOne(Wrappers.<DeptEntity>lambdaQuery()
                    .eq(DeptEntity::getParentDeptCode, deptPo.getParentDeptCode())
                    .orderByDesc(DeptEntity::getSort).last("limit 1"));
            deptEntity.setSort(Objects.isNull(sortType) ? 1 : sortType.getSort() + 1);
        }

        //创建顶级职务分组
        AuthorityPositionGroupPo authorityPositionGroupPo = new AuthorityPositionGroupPo();
        authorityPositionGroupPo.setPositionGroupCode(deptEntity.getDeptCode());
        authorityPositionGroupPo.setPositionGroupName(deptPo.getDeptName());
        authorityPositionGroupPo.setDeptCode(deptEntity.getDeptCode());
        authorityPositionGroupPo.setPositionGroupNumber(deptEntity.getDeptNumber());
        authorityPositionGroupPo.setSort(deptEntity.getSort());
        this.authorityPositionGroupService.add(authorityPositionGroupPo);
        this.save(deptEntity);
        return deptEntity;
    }

    /**
     * 删除部门或机构
     * @param
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean deleteDept(String deptCode) {
        //查看该部门是否有下级部门

        int countDept = this.count(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getParentDeptCode, deptCode));
        if (countDept > 0) {
            throw ExceptionUtil.create(BusinessErrorEnum.DEPT_DELETE_ERROR);
        }
        int countUser = authorityUserDeptService.count(Wrappers.<AuthorityUserDept>lambdaQuery().eq(AuthorityUserDept::getDeptCode, deptCode));
        if (countUser > 0){
            throw new BusinessException(BusinessErrorEnum.DEPT_CANNOT_DELETE);
        }
        boolean pos = this.authorityPositionGroupService.deleteByCode(deptCode);
        //删除该部门或机构
        boolean dept= this.remove(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getDeptCode,deptCode));
        return pos || dept ;
    }

    /**
     * 更新部门
     * @param deptPo 编辑po
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public DeptEntity updateDept(DeptPo deptPo) {
        int count = this.count(Wrappers.<DeptEntity>lambdaQuery()
                .eq(DeptEntity::getDeptName, deptPo.getDeptName())
                .ne(DeptEntity::getDeptCode,deptPo.getDeptCode()));
        if (count > 0) {
            throw ExceptionUtil.create(BusinessErrorEnum.DEPT_NAME_REPEAT);
        }
        if(StrUtil.isNotBlank(deptPo.getDeptNumber())&&this.count(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getDeptNumber, deptPo.getDeptNumber()).
                ne(DeptEntity::getDeptCode,deptPo.getDeptCode()))>0){
            throw ExceptionUtil.create(BusinessErrorEnum.DEPT_NUMBER_REPEAT);
        }
        DeptEntity current = this.getOne(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getDeptCode, deptPo.getDeptCode()));

        if(current.getDeptName().contains(Constants.DEPT_SUFFIX)){
            current.setDeptName(deptPo.getDeptName()+Constants.DEPT_SUFFIX);
        }else{
            current.setDeptName(deptPo.getDeptName());
        }
        current.setRemark(deptPo.getRemark());
        current.setDeptTypeCode(deptPo.getDeptTypeCode());
        current.setDeptNumber(deptPo.getDeptNumber());
        if(StrUtil.isNotBlank(deptPo.getParentDeptCode())&&current.getParentDeptCode().equals(deptPo.getParentDeptCode())){
             this.update(current,Wrappers.<DeptEntity>lambdaUpdate().eq(DeptEntity::getDeptCode,deptPo.getDeptCode()));
        }
        else if(StrUtil.isBlank(deptPo.getParentDeptCode())&&current.getParentDeptCode().equals(Constants.PARENT_CODE)){
             this.update(current,Wrappers.<DeptEntity>lambdaUpdate().eq(DeptEntity::getDeptCode,deptPo.getDeptCode()));
        }
        else {
            //获取上级全路径

            if (StrUtil.isNotBlank(deptPo.getParentDeptCode())) {
                //得到上级分类的详细信息
                DeptEntity parent = this.getOne(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getDeptCode, deptPo.getParentDeptCode()));
                //全路径拼接
                String searchChar = current.getFullPath();
                String newChar = parent.getFullPath() + Constants.DELIMITER + deptPo.getDeptCode();
                current.setFullPath(newChar);
                current.setParentDeptCode(deptPo.getParentDeptCode());

                this.deptDao.batchUpdateFullPath(searchChar, newChar);

            } else {

                String searchChar = current.getFullPath();
                String newChar = deptPo.getOrganizationCode() + Constants.DELIMITER + deptPo.getDeptCode();
                current.setFullPath(newChar);

                current.setParentDeptCode(deptPo.getOrganizationCode());
                this.deptDao.batchUpdateFullPath(searchChar, newChar);
            }
            DeptEntity sortType = this.getOne(Wrappers.<DeptEntity>lambdaQuery()
                    .eq(DeptEntity::getDeptCode, current.getParentDeptCode())
                    .orderByDesc(DeptEntity::getSort).last("limit 1"));
            current.setSort(Objects.isNull(sortType) ? 1 : sortType.getSort() + 1);
           this.update(current, Wrappers.<DeptEntity>lambdaUpdate().eq(DeptEntity::getDeptCode, deptPo.getDeptCode()));
        }
        AuthorityPositionGroupPo authorityPositionGroupPo = new AuthorityPositionGroupPo();
        authorityPositionGroupPo.setPositionGroupCode(current.getDeptCode());
        authorityPositionGroupPo.setPositionGroupName(deptPo.getDeptName());
        authorityPositionGroupPo.setDeptCode(current.getDeptCode());
        authorityPositionGroupPo.setPositionGroupNumber(current.getDeptNumber());
        authorityPositionGroupPo.setSort(current.getSort());
        this.authorityPositionGroupService.update(authorityPositionGroupPo);
        return current;
    }

    /**
     * 查询部门或机构信息
     *
     * @param deptUpdatePo 部门编码
     * @return 部门详情vo
     */
    @Override
    public DeptDetailVo findByDeptCode(DeptPo deptUpdatePo) {
        DeptEntity deptEntity = this.getOne(Wrappers.<DeptEntity>lambdaQuery().eq(DeptEntity::getDeptCode, deptUpdatePo.getDeptCode()));
        DeptDetailVo deptDetailVo = ConvertUtils.sourceToTarget(deptEntity, DeptDetailVo.class);
        deptDetailVo.setCreateTime(deptEntity.getCreateTime());
        return deptDetailVo;
    }

    //解析并找到父节点
    private List<DeptTreeVo> buildTree(List<DeptTreeVo> list) {
        //找出顶级节点编码
        Set<String> pList= list.stream().collect(Collectors.groupingBy(DeptTreeVo::getParentDeptCode)).keySet();
        Set<String> cList= list.stream().collect(Collectors.groupingBy(DeptTreeVo::getDeptCode)).keySet();
        List<String> topList = pList.stream().filter(item -> !cList.contains(item)).collect(toList());

        List<DeptTreeVo> last = new ArrayList<>();
        for (String parentCode : topList) {
            last.addAll(this.getTreeListFromCurrent(parentCode,list));
        }
        return last;
    }
    /**
     * 解析树形数据
     * @param currentId
     * @param entityList
     * @return
     */
    public List<DeptTreeVo> getTreeListFromCurrent(String currentId, List<DeptTreeVo> entityList) {

        if(entityList==null || entityList.size()==0) return new ArrayList<>();

        List<DeptTreeVo> resultList = new ArrayList<>();

        //获取顶层元素集合
        for (DeptTreeVo entity : entityList) {
            if(currentId.equals(entity.getParentDeptCode())){
                resultList.add(entity);
            }
        }

        //获取每个顶层元素的子数据集合
        for (DeptTreeVo entity : resultList) {
            entity.setChildren(getSubList(entity.getDeptCode(), entityList));
        }
        return resultList;
    }

    /**
     * 获取子数据集合
     * @param deptCode
     * @param subList
     */
    private  List<DeptTreeVo> getSubList(String deptCode, List<DeptTreeVo> subList) {
        List<DeptTreeVo> childList = new ArrayList<>();
        //子集的直接子对象
        for (DeptTreeVo entity : subList) {
            if(deptCode.equals( entity.getParentDeptCode())){
                childList.add(entity);
            }
        }
        //递归退出条件
        if(childList.size() == 0){
            return null;
        }
        //子集的间接子对象
        for (DeptTreeVo entity : childList) {
            entity.setChildren(getSubList(entity.getDeptCode(), subList));
        }

        return childList;
    }
    private List<DeptTreeVo> diGuiDeptTree(List<DeptEntity> allList,List<DeptTreeVo> returnList){
        returnList.stream().forEach(a->{
            List<DeptEntity> child = allList.stream().filter(b -> {
                return b.getParentDeptCode().equals(a.getDeptCode());
            }).collect(toList());
            List<DeptTreeVo> childList = new LinkedList<>();
            if (child!=null && child.size()>0){
                child.stream().forEach(b->{
                    DeptTreeVo vo = new DeptTreeVo();
                    BeanUtils.copyProperties(b,vo);
                    childList.add(vo);
                });
                a.setChildren(childList);
                diGuiDeptTree(allList,childList);
            }
        });
        return returnList;
    }
}
